using Microsoft.Extensions.Logging;
using System.Data.SqlClient;
using System.Threading.Tasks;
using System.Text.Json;
using System.Text.Encodings.Web;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Extensions.DependencyInjection;

namespace Beauty.Net.Middleware
{
    // 控制台日志存储实现
    public class ConsoleLogStorage : ILogStorage
    {
        private readonly ILogger<ConsoleLogStorage> _logger;

        public ConsoleLogStorage(ILogger<ConsoleLogStorage> logger)
        {
            _logger = logger;
        }

        public Task SaveLogAsync(ApiLog log)
        {
            // 创建一个自定义的JsonSerializerOptions，确保不会添加额外的转义
            var jsonOptions = new JsonSerializerOptions
            {
                WriteIndented = false,
                // 设置编码器以防止中文字符和特殊字符被过度转义
                Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
            };
            string logJson = JsonSerializer.Serialize(log, jsonOptions);
            _logger.LogInformation($"[Api Log] {logJson}");
            return Task.CompletedTask;
        }
    }

    // MySQL日志存储实现
    public class MySqlLogStorage : ILogStorage
    {
        private readonly LoggingOptions _options;
        private readonly ILogger<MySqlLogStorage> _logger;

        public MySqlLogStorage(LoggingOptions options, ILogger<MySqlLogStorage> logger)
        {
            _options = options;
            _logger = logger;
        }

        public async Task SaveLogAsync(ApiLog log)
        {
            try
            {
                using (var connection = new SqlConnection(_options.MySqlConnectionString))
                {
                    await connection.OpenAsync();
                    string query = $@"
                        INSERT INTO {_options.MySqlTableName} 
                        (RequestId, Path, Method, RequestBody, ResponseBody, StatusCode, ResponseTimeMs, ExceptionMessage, ExceptionStackTrace, Timestamp) 
                        VALUES (@RequestId, @Path, @Method, @RequestBody, @ResponseBody, @StatusCode, @ResponseTimeMs, @ExceptionMessage, @ExceptionStackTrace, @Timestamp)
                    ";

                    using (var command = new SqlCommand(query, connection))
                    {
                        command.Parameters.AddWithValue("@RequestId", log.RequestId);
                        command.Parameters.AddWithValue("@Path", log.Path);
                        command.Parameters.AddWithValue("@Method", log.Method);
                        command.Parameters.AddWithValue("@RequestBody", log.RequestBody ?? (object)DBNull.Value);
                        command.Parameters.AddWithValue("@ResponseBody", log.ResponseBody ?? (object)DBNull.Value);
                        command.Parameters.AddWithValue("@StatusCode", log.StatusCode);
                        command.Parameters.AddWithValue("@ResponseTimeMs", log.ResponseTimeMs);
                        command.Parameters.AddWithValue("@ExceptionMessage", log.ExceptionMessage ?? (object)DBNull.Value);
                        command.Parameters.AddWithValue("@ExceptionStackTrace", log.ExceptionStackTrace ?? (object)DBNull.Value);
                        command.Parameters.AddWithValue("@Timestamp", log.Timestamp);

                        await command.ExecuteNonQueryAsync();
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to save log to MySQL");
                throw;
            }
        }
    }

    // Elasticsearch日志存储实现（简化版本，实际使用需要安装Elasticsearch客户端）
    public class ElasticsearchLogStorage : ILogStorage
    {
        private readonly LoggingOptions _options;
        private readonly ILogger<ElasticsearchLogStorage> _logger;

        public ElasticsearchLogStorage(LoggingOptions options, ILogger<ElasticsearchLogStorage> logger)
        {
            _options = options;
            _logger = logger;
        }

        public async Task SaveLogAsync(ApiLog log)
        {
            try
            {
                // 这里是简化实现，实际使用时应该使用Elasticsearch官方客户端
                // 例如：Elasticsearch.Net和Nest包
                // 使用与ConsoleLogStorage相同的JSON序列化选项，确保一致的转义行为
                var jsonOptions = new JsonSerializerOptions
                {
                    WriteIndented = false,
                    Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
                };
                string logJson = JsonSerializer.Serialize(log, jsonOptions);
                
                using (var httpClient = new System.Net.Http.HttpClient())
                {
                    var response = await httpClient.PostAsync(
                        $"{_options.ElasticsearchUri}/{_options.ElasticsearchIndex}/_doc",
                        new System.Net.Http.StringContent(logJson, System.Text.Encoding.UTF8, "application/json"));

                    response.EnsureSuccessStatusCode();
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to save log to Elasticsearch");
                throw;
            }
        }
    }

    // MongoDB日志存储实现（简化版本，实际使用需要安装MongoDB客户端）
    public class MongoDbLogStorage : ILogStorage
    {
        private readonly LoggingOptions _options;
        private readonly ILogger<MongoDbLogStorage> _logger;

        public MongoDbLogStorage(LoggingOptions options, ILogger<MongoDbLogStorage> logger)
        {
            _options = options;
            _logger = logger;
        }

        public Task SaveLogAsync(ApiLog log)
        {
            try
            {
                // 这里是简化实现，实际使用时应该使用MongoDB官方客户端
                // 例如：MongoDB.Driver包
                _logger.LogInformation("MongoDB log storage would save log here with official driver");
                
                // 实际代码示例（注释状态，需要安装MongoDB.Driver）:
                /*
                var client = new MongoDB.Driver.MongoClient(_options.MongoDbConnectionString);
                var database = client.GetDatabase(_options.MongoDbDatabaseName);
                var collection = database.GetCollection<ApiLog>(_options.MongoDbCollectionName);
                await collection.InsertOneAsync(log);
                */
                return Task.CompletedTask;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to save log to MongoDB");
                throw;
            }
        }
    }

    // 日志存储工厂类
    public class LogStorageFactory
    {
        private readonly IServiceProvider _serviceProvider;

        public LogStorageFactory(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        public ILogStorage CreateLogStorage(LoggingOptions options)
        {
            switch (options.StorageType)
            {
                case LogStorageType.MySql:
                    return new MySqlLogStorage(options, _serviceProvider.GetRequiredService<ILogger<MySqlLogStorage>>());
                case LogStorageType.Elasticsearch:
                    return new ElasticsearchLogStorage(options, _serviceProvider.GetRequiredService<ILogger<ElasticsearchLogStorage>>());
                case LogStorageType.MongoDB:
                    return new MongoDbLogStorage(options, _serviceProvider.GetRequiredService<ILogger<MongoDbLogStorage>>());
                case LogStorageType.Console:
                default:
                    return new ConsoleLogStorage(_serviceProvider.GetRequiredService<ILogger<ConsoleLogStorage>>());
            }
        }
    }
}